package com.mp.approvalreq.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.dao.*;
import com.mp.approvalreq.dao.impl.*;
import com.mp.approvalreq.entity.*;
import com.mp.approvalreq.entity.dto.TemplateDTO;
import com.mp.approvalreq.service.RequestServiceServant;
import com.mp.approvalreq.util.*;
import com.mp.user.entity.User;
import com.mp.user.service.UserServicePrx;
import com.mp.user.util.UserUtils;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.exception.enums.ApprovalRespCodeDesc;
import com.plusmoney.jdbc.util.DBUtils;
import com.plusmoney.util.BeanUtils;
import com.plusmoney.util.DateTimeHelper;
import com.plusmoney.util.Utils;
import com.qq.tars.client.util.ServantUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

public class RequestServantImpl implements RequestServiceServant {

    private static final Logger logger = LoggerFactory.getLogger(RequestServantImpl.class);

    @Override
    public List<Request> getWhatToApprove(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);

            List<Integer> allRequestIds = flowDao.selectNeedUserApproveIds(query.getCompanyId(), query.getCompanyInfoId());

            return getRequests(query, allRequestIds, redDao, requestDao, null);
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getUserApproved(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);

            if (!query.querySelf()) {
                UserServicePrx userService = ServantUtils.getObject(UserServicePrx.class);
                User user = userService.getUserByContactId(query.getApplicant());
                query.setApplicantCiid(user.getCompanyInfoId());
            } else {
                query.setApplicantCiid(query.getCompanyInfoId());
            }

            List<Integer> allRequestIds = flowDao.selectRequestIdsApprovedByCompanyInfoId(query.getCompanyId(), query.getApplicantCiid(), query.getOrderBy());

            return getRequests(query, allRequestIds, redDao, requestDao, null);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getUserRequestList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);

            List<Integer> allRequestIds = requestDao.selectRequestIdsByCompanyInfoId(query.getContactId(), query.getCompanyInfoId(),
                    query.getFinishedSequence(), query.getOrderBy());

            return getRequests(query, allRequestIds, redDao, requestDao, null);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getUserSubordinateRequestList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);

            List<Integer> allRequestIds = requestDao.selectRequestIdsByContactId(query.getApplicant(), query.getOrderBy());

            return getRequests(query, allRequestIds, redDao, requestDao, null);
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getParticipateRequestList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            ParticipantDao participantDao = new ParticipantDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);

            List<Integer> allRequestIds = participantDao.selectParticipateRequestIdsByCompanyInfoId(query.getCompanyId(),
                    query.getCompanyInfoId(), query.getFinishedSequence(), query.getFinancialStatusSequence(), query.getOrderBy());

            List<Integer> redPointIds = participantDao.selectUnReadRequestIds(query.getCompanyId(), query.getCompanyInfoId());

            return getRequests(query, allRequestIds, redDao, requestDao, redPointIds);
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getWhatToFile(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            CcDao ccDao = new CcDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);

            List<Integer> allRequestIds = ccDao.selectNeedToFileRequestIds(query.getCompanyId(), query.getCompanyInfoId());

            List<Integer> ccReadPoints = ccDao.selectCcUnReadRequestIds(query.getCompanyId(), query.getCompanyInfoId());

            return getRequests(query, allRequestIds, redDao, requestDao, ccReadPoints);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getUserFiledRequestList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);

            List<Integer> requestIds = ccDao.selectMyFiledRequestIds(query.getCompanyId(), query.getCompanyInfoId(), query.getOrderBy());

            return getRequests(query, requestIds, redDao, requestDao, null);
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> searchRequest(Query query) throws Throwable {
        try {
            List<Request> result;
            switch (query.getSearchType()) {
                case 1:
                    //在抄送我的未归档的里搜
                    result = searchInCcToMe(query);
                    break;
                case 2:
                    //在我已归档的里搜
                    result = searchInMyFiled(query);
                    break;
                case 3:
                    //搜索某人申请的
                    result = searchInSomeoneApplied(query);
                    break;
                case 4:
                    //搜索某人处理的
                    result = searchInSomeoneHandled(query);
                    break;
                case 5:
                    //3,4
                    result = searchInSomeone(query);
                    break;
                case 6:
                    //1,2
                    result = searchInMyCcAndArchived(query);
                    break;
                case 7:
                    //我参与的
                    result = searchInWhatITookPartIn(query);
                    break;
                case 8:
                    //待处理的
                    result = searchWhatToApprove(query);
                    break;
                default:
                    throw new RpcServerLogicalException(ApprovalRespCodeDesc.WRONG_OPERATION);
            }

            return result;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        }
    }

    /**
     * 在抄送我的里搜
     *
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchInCcToMe(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {

            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);

            // 关键词搜人
            Set<Integer> keywordIds = searchUserByKeyword(query);
            // 模板id
            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);
            // 搜索
            List<Request> list = searchDao.selectRequestApprovedCcToMe(query, templateIds, keywordIds, Cc.NEED_FILE);
            // 分页
            list = sortAndPagingWithRedPoint(query, list, redDao);

            requestDecoration(list, query);

            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * 搜索某人的
     *
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchInSomeone(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);

            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);

            if (query.getApplicant() > 0) {
                // 搜下属处理的
                User applicant = userServicePrx.getUserByContactId(query.getApplicant());
                query.setCompanyInfoId(applicant.getCompanyInfoId());
                query.setApplicantCiid(applicant.getCompanyInfoId());
            } else if (query.getApplicant() == -1) {
                query.setCompanyInfoId(0);
                query.setApplicantCiid(0);
            } else {
                query.setApplicantCiid(query.getCompanyInfoId());
            }
            // 关键词搜人
            Set<Integer> keywordIds = searchUserByKeyword(query);
            // 模板id
            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);

            List<Request> list1 = searchDao.selectRequestApprovedByUser(query, templateIds, keywordIds);
            List<Request> list2 = searchDao.selectRequestAppliedByUser(query, templateIds);

            List<Request> list = ListUtils.union(list1, list2).stream().distinct().collect(Collectors.toList());

            list = sortAndPagingWithRedPoint(query, list, redDao);
            requestDecoration(list, query);
            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * 在我归档的页面里搜索
     *
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchInMyFiled(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);

            // 关键词搜人
            Set<Integer> keywordIds = searchUserByKeyword(query);
            // 模板id
            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);
            // 搜索
            List<Request> list = searchDao.selectRequestApprovedCcToMe(query, templateIds, keywordIds, Cc.HAD_FILED);
            // 分页
            list = sortAndPagingWithRedPoint(query, list, redDao);

            requestDecoration(list, query);

            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * 在抄送我的里搜
     *
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchInMyCcAndArchived(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);

            // 关键词搜人
            Set<Integer> keywordIds = searchUserByKeyword(query);
            // 模板id
            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);
            // 搜索
            List<Request> list1 = searchDao.selectRequestApprovedCcToMe(query, templateIds, keywordIds, Cc.NEED_FILE);
            List<Request> list2 = searchDao.selectRequestApprovedCcToMe(query, templateIds, keywordIds, Cc.HAD_FILED);
            List<Request> list = ListUtils.union(list1, list2);

            // 分页
            list = sortAndPagingWithRedPoint(query, list, redDao);

            requestDecoration(list, query);

            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * 搜我参与的
     *
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchInWhatITookPartIn(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);

            // 关键词搜人
            Set<Integer> keywordIds = searchUserByKeyword(query);
            // 模板id
            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);

            // 搜索
            List<Request> list = searchDao.selectRequestParticipatedByUser(query, templateIds, keywordIds);

            // 分页
            list = sortAndPagingWithRedPoint(query, list, redDao);

            requestDecoration(list, query);

            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchWhatToApprove(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);
            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);

            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);
            Set<Integer> keywordIds = searchUserByKeyword(query);
            // 搜索
            List<Request> list = searchDao.selectRequestNeedUserApprove(query, templateIds, keywordIds);

            // 分页
            list = sortAndPagingWithRedPoint(query, list, redDao);

            requestDecoration(list, query);

            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * 搜索某人申请的
     *
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchInSomeoneApplied(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RedDao redDao = new RedDaoImpl(connection);


            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);
            if (query.getApplicant() > 0) {
                UserServicePrx userService = ServantUtils.getObject(UserServicePrx.class);
                User applicant = userService.getUserByContactId(query.getApplicant());
                query.setApplicantCiid(applicant.getCompanyInfoId());
            } else {
                query.setApplicantCiid(query.getCompanyInfoId());
            }

            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);
            // 搜索
            List<Request> list = searchDao.selectRequestAppliedByUser(query, templateIds);
            // 分页
            list = sortAndPagingWithRedPoint(query, list, redDao);

            requestDecoration(list, query);

            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * 搜索某人处理过的
     *
     * @param query
     * @return
     * @throws Throwable
     */
    private List<Request> searchInSomeoneHandled(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            RedDao redDao = new RedDaoImpl(connection);

            SearchDao searchDao = new SearchDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);

            // 下属id集合
            if (query.getApplicant() > 0) {
                // 搜下属处理的
                User applicant = userServicePrx.getUserByContactId(query.getApplicant());
                query.setApplicantCiid(applicant.getCompanyInfoId());
            } else {
                query.setApplicantCiid(query.getCompanyInfoId());
            }
            // 关键词搜人
            Set<Integer> keywordIds = searchUserByKeyword(query);
            // 模板id
            List<Integer> templateIds = getTemplateIds(query, selectTemplateDao);
            // 搜索
            List<Request> list = searchDao.selectRequestApprovedByUser(query, templateIds, keywordIds);
            // 分页
            list = sortAndPagingWithRedPoint(query, list, redDao);

            requestDecoration(list, query);
            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    /**
     * 设置红点并分页排序
     *
     * @param query
     * @param list
     * @param redDao
     * @return
     */
    private List<Request> sortAndPagingWithRedPoint(Query query, List<Request> list, RedDao redDao) throws Throwable {
        if (Utils.isEmpty(list)) {
            return list;
        }
        Map<Integer, List<MessageRead>> redPointMap = redDao.selectUserRedPointMap(query.getCompanyInfoId());

        RequestUtils.setRedPoint(list, redPointMap);

        RequestUtils.sort(list, query.getOrderBy());

        int totalCount = list.size();
        list = RequestUtils.paging(query, list);

        list.forEach(request -> request.setTotalCount(totalCount));
        return list;
    }

    /**
     * 获取搜索模板id
     *
     * @param query
     * @param selectTemplateDao
     * @return
     * @throws SQLException
     */
    private List<Integer> getTemplateIds(Query query, SelectTemplateDao selectTemplateDao) throws SQLException {
        List<Integer> templateIds = new ArrayList<>();
        if (StringUtils.isNotBlank(query.getAncestorIds())) {
            Map<Integer, List<Integer>> templateIdMap = selectTemplateDao.selectTemplateIdsByAncestorIds(query.getAncestorIds());
            for (List<Integer> ids : templateIdMap.values()) {
                templateIds.addAll(ids);
            }
        }
        if (query.getCompanyId() == 12 && Utils.isNotEmpty(templateIds)) {
            try {
                TemplateDTO templateDTO = selectTemplateDao.getTemplateDTO(query.getCompanyId(), templateIds.get(0));
                List<Integer> idList = selectTemplateDao.selectTemplateIdsByName(query.getCompanyId(), templateDTO.getTemplateName());
                templateIds.addAll(idList);
                templateIds = templateIds.stream().distinct().collect(Collectors.toList());
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
            }
        }
        return templateIds;
    }


    private Set<Integer> searchUserByKeyword(Query query) {
        Set<Integer> keywordIds = new HashSet<>();

        try {
            if (StringUtils.isNotBlank(query.getKeywords())) {
                UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
                List<User> userList = userServicePrx.searchUserListLikeNames(query.getCompanyId(), query.getKeywords());
                keywordIds = userList.stream().map(User::getCompanyInfoId).collect(Collectors.toSet());
            }
            logger.info("关键词搜用户:{}", keywordIds);
        } catch (Throwable throwable) {
            logger.error("搜索出错", throwable);
        }
        return keywordIds;
    }


    /**
     * @param query
     * @param allRequestIds
     * @param redDao
     * @param requestDao
     * @param redPointIds   抄送/参与红点
     * @return
     * @throws Throwable
     */
    private List<Request> getRequests(Query query, List<Integer> allRequestIds, RedDao redDao,
                                      RequestDao requestDao, List<Integer> redPointIds) throws Throwable {
        if (Utils.isEmpty(allRequestIds)) {
            return new ArrayList<>();
        }
        Map<Integer, List<MessageRead>> redPointMap = redDao.selectUserRedPointMap(query.getCompanyInfoId());

        // 置顶带红点审批
        if (query.defaultOrderBy()) {
            if (Utils.isNull(redPointIds)) {
                redPointIds = new ArrayList<>();
            }
            logger.info("置顶红点:{},{}", redPointMap.keySet(), redPointIds);
            RequestUtils.stickyRedPoint(allRequestIds, redPointMap, redPointIds);
        }

        // 分页审批id
        List<Integer> requestIds = RequestUtils.paging(query, allRequestIds);
        // 获取审批信息
        List<Request> list = requestDao.selectRequestByIds(Utils.list2string(requestIds));

        list.forEach(request -> request.setTotalCount(allRequestIds.size()));

        // 设置评论红点
        RequestUtils.setRedPoint(list, redPointMap);
        // 设置抄送未读红点
        RequestUtils.setRedPoint(redPointIds, list);

        // 排序
        list.sort(Comparator.comparingInt(o -> allRequestIds.indexOf(o.getRequestDkey())));

        // 设置相关信息
        requestDecoration(list, query);

        return list;
    }

    private void requestDecoration(List<Request> requests, Query query) throws Throwable {
        if (Utils.isEmpty(requests)) {
            return;
        }
        Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);

        String requestIds = Utils.collection2string(requestMap.keySet());
        String templateIds = Utils.list2string(RequestUtils.getTemplateIds(requests));

        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            ComponentDao componentDao = new ComponentImpl(connection);

            Map<Integer, Template> templateMap = templateDao.selectTemplateByIds(templateIds);
            RequestUtils.setTemplateInfo(requests, templateMap);

            Map<Integer, List<TemplateComponent>> componentMap = componentDao.selectComponentMapByRequestIds(requestIds);
            Map<Integer, Map<Integer, List<GroupContent>>> groupComponentMap = componentDao.selectGroupComponentByRequestIds(requestIds);
            RequestUtils.setComponentInfo(requests, componentMap, groupComponentMap);

            setSummaryInfo(connection, requestMap, query);

            simplifyData(requests, query);
            if (!query.canHidePeopleList() || "getMissionRelatedRequestList".equals(query.getFrom()) || "getRelatedRequestList".equals(query.getFrom())) {
                getRequestsPeopleName(requests, query.getCompanyId());
            }
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private void setSummaryInfo(Connection connection, Map<Integer, Request> requestMap, Query query) throws Throwable {
        List<Integer> leaveIds = new ArrayList<>(), outdoorIds = new ArrayList<>(), overtimeIds = new ArrayList<>(),
                appendSignIds = new ArrayList<>(), expenseIds = new ArrayList<>(), otherIds = new ArrayList<>();

        for (Request request : requestMap.values()) {
            int requestId = request.getRequestDkey();
            switch (request.getDefaultType()) {
                case Template.LEAVE:
                case Template.COMPENSATORY_LEAVE:
                case Template.DAYS_OFF:
                    leaveIds.add(requestId);
                    break;
                case Template.OUTDOOR:
                case Template.BUSINESS_TRIP:
                    outdoorIds.add(requestId);
                    break;
                case Template.WORK_OVERTIME:
                    overtimeIds.add(requestId);
                    break;
                case Template.APPEND_SIGN:
                    appendSignIds.add(requestId);
                    break;
                case Template.EXPENSES:
                case Template.PURCHASE:
                    expenseIds.add(requestId);
                    break;
                default:
                    otherIds.add(requestId);
            }
        }
        Map<Integer, Summary> summaryMap = new HashMap<>();
        if (Utils.isNotEmpty(leaveIds)) {
            summaryMap.putAll(getLeaveSummaryMap(connection, requestMap, leaveIds));
        }
        if (Utils.isNotEmpty(outdoorIds)) {
            summaryMap.putAll(getOutdoorSummaryMap(connection, requestMap, outdoorIds));
        }
        if (Utils.isNotEmpty(overtimeIds)) {
            summaryMap.putAll(getOvertimeSummaryMap(connection, requestMap, overtimeIds));
        }
        if (Utils.isNotEmpty(appendSignIds)) {
            summaryMap.putAll(getAppendSignSummaryMap(connection, requestMap, appendSignIds));
        }
        if (Utils.isNotEmpty(expenseIds)) {
            summaryMap.putAll(getExpenseSummaryMap(connection, requestMap, expenseIds));
        }
        if (Utils.isNotEmpty(otherIds)) {
            summaryMap.putAll(getOtherSummaryMapV2(requestMap, otherIds));
        }

        if (Utils.isNotNull(query)) {
            if ("1".equals(query.getOrderBy())) {
                // 按申请时间排序
                for (Map.Entry<Integer, Summary> entry : summaryMap.entrySet()) {
                    Request request = requestMap.get(entry.getKey());
                    Summary summary = entry.getValue();
                    summary.setTime(SummaryUtils.getDateTimeDesc(request.getCreateTimestamp()) + "申请");
                }
            } else if ("2".equals(query.getOrderBy())) {
                // 按处理时间排序
                for (Map.Entry<Integer, Summary> entry : summaryMap.entrySet()) {
                    Request request = requestMap.get(entry.getKey());
                    if (!ValidateUtil.isValidDateTimeMills(request.getLatestApprovedTime())) {
                        continue;
                    }
                    Summary summary = entry.getValue();
                    summary.setTime(SummaryUtils.getDateTimeDesc(DateTimeHelper.parse(request.getLatestApprovedTime())) + "处理");
                }
            }
        }

        logger.info("summaryMap:{}", JSONObject.toJSONString(summaryMap));
        requestMap.values().forEach(request -> request.setSummary(summaryMap.get(request.getRequestDkey())));
    }

    private Map<Integer, Summary> getOtherSummaryMapV2(Map<Integer, Request> requestMap, List<Integer> otherIds) {
        Map<Integer, Summary> map = new HashMap<>();
        for (Integer requestId : otherIds) {
            Request request = requestMap.get(requestId);
            Summary summary = SummaryUtils.getOtherSignSummary(request);
            map.put(requestId, summary);
        }
        return map;
    }

    private Map<Integer, Summary> getExpenseSummaryMap(Connection connection, Map<Integer, Request> requestMap, List<Integer> expenseIds) throws Throwable {
        Map<Integer, Summary> map = new HashMap<>();
        ExpenseDao expenseDao = new ExpenseDaoImpl(connection);
        Map<Integer, List<Expense>> expenseMap = expenseDao.selectExpensesByRequestIds(Utils.list2string(expenseIds));
        for (Map.Entry<Integer, List<Expense>> entry : expenseMap.entrySet()) {
            Request request = requestMap.get(entry.getKey());
            Summary summary = SummaryUtils.getExpenseSummary(request, entry.getValue());
            map.put(entry.getKey(), summary);
        }
        return map;
    }

    private Map<Integer, Summary> getAppendSignSummaryMap(Connection connection, Map<Integer, Request> requestMap, List<Integer> appendSignIds) throws Throwable {
        Map<Integer, Summary> map = new HashMap<>(appendSignIds.size());
        AppendSignDao appendSignDao = new AppendSignDaoImpl(connection);
        Map<Integer, List<AppendSign>> appendSignMap = appendSignDao.selectAppendSignsByRequestIds(Utils.list2string(appendSignIds));
        for (Map.Entry<Integer, List<AppendSign>> entry : appendSignMap.entrySet()) {
            Request request = requestMap.get(entry.getKey());
            Summary summary = SummaryUtils.getAppendSignSummary(request, entry.getValue());
            map.put(entry.getKey(), summary);
        }
        return map;
    }

    private Map<Integer, Summary> getOvertimeSummaryMap(Connection connection, Map<Integer, Request> requestMap, List<Integer> overtimeIds) throws Throwable {
        Map<Integer, Summary> map = new HashMap<>(overtimeIds.size());
        OvertimeDao overtimeDao = new OvertimeDaoImpl(connection);
        Map<Integer, List<Overtime>> overtimeMap = overtimeDao.selectOvertimesByRequestIds(Utils.list2string(overtimeIds));
        for (Map.Entry<Integer, List<Overtime>> entry : overtimeMap.entrySet()) {
            Request request = requestMap.get(entry.getKey());
            Summary summary = SummaryUtils.getOvertimeSummary(request, entry.getValue());
            map.put(entry.getKey(), summary);
        }
        return map;
    }

    private Map<Integer, Summary> getOutdoorSummaryMap(Connection connection, Map<Integer, Request> requestMap, List<Integer> outdoorIds) throws Throwable {
        Map<Integer, Summary> map = new HashMap<>(outdoorIds.size());
        OutdoorDao outdoorDao = new OutdoorDaoImpl(connection);
        Map<Integer, Outdoor> outdoorMap = outdoorDao.selectOutdoorsByRequestIds(Utils.list2string(outdoorIds));
        for (Outdoor outdoor : outdoorMap.values()) {
            Request request = requestMap.get(outdoor.getRequestId());
            Summary summary = SummaryUtils.getOutdoorSummary(request, outdoor);
            map.put(outdoor.getRequestId(), summary);
        }
        return map;
    }

    private Map<Integer, Summary> getLeaveSummaryMap(Connection connection, Map<Integer, Request> requestMap, List<Integer> leaveIds) throws Throwable {
        Map<Integer, Summary> map = new HashMap<>(leaveIds.size());
        LeaveDao leaveDao = new LeaveDaoImpl(connection);
        Map<Integer, Leave> leaveMap = leaveDao.selectLeavesByRequestIds(Utils.list2string(leaveIds));
        for (Leave leave : leaveMap.values()) {
            Request request = requestMap.get(leave.getRequestId());
            Summary summary = SummaryUtils.getLeaveSummary(request, leave);
            map.put(leave.getRequestId(), summary);
        }
        return map;
    }


    /**
     * 过度阶段简化返回值,后续直接改sql
     *
     * @param requests
     * @param query
     */
    private void simplifyData(List<Request> requests, Query query) {
        for (Request request : requests) {
            request.setAllJudger(null);
            request.setCc(null);
            request.setCcCiid(null);
            request.setWhoConfirm(null);
            request.setWhoConfirmCiid(null);
            request.setWhoRefused(null);
            request.setWhoRefusedCiid(null);
            request.setWhoTheNext(null);
            request.setWhoTheNextCiid(null);
            request.setCheckedTime(null);
            request.setFinallyConfirmedTime(null);
            request.setCreateTimestamp(null);
            request.setRequestName(null);
            request.setRequestStep(null);
        }
        if (!query.canHideListField()) {
            return;
        }
        for (Request request : requests) {
            if ("getMissionRelatedRequestList".equals(query.getFrom())
                    || "getRelatedRequestList".equals(query.getFrom())) {
                List<TemplateComponent> list = new ArrayList<>();
                if (request.getDefaultType() == Template.OUTDOOR) {
                    Map<Integer, TemplateComponent> componentMap = ComponentUtils.getComponentMap(request.getComponentsContent());
                    list.add(componentMap.get(1));
                    list.add(componentMap.get(2));
                }
                request.setComponentsContent(list);
                request.setTemplateComponent(JSONObject.toJSONString(list));
            } else {
                request.setComponentsContent(null);
                request.setTemplateComponent(null);
            }
            request.setPriorityShow(null);
            request.setLatestApprovedTime(null);
            request.setRequestTime(null);
            request.setFinallyCcTime(null);
            request.setCreateTimestamp(null);
            request.setCreateTime(null);
            request.setOuterPosition(null);
        }
    }

    private void getRequestsPeopleName(List<Request> list, Integer companyId) throws Throwable {
        UserServicePrx userService = ServantUtils.getObject(UserServicePrx.class);

        String people = getPeopleIds(list);
        List<User> users = userService.getUserBaseInfoListByContactIds(companyId, people);
        Map<Integer, String> idName = new HashMap<>();
        for (User user1 : users) {
            idName.put(user1.getContactId(), user1.getContactName());
        }

        for (int i = 0; i < list.size(); i++) {
            Request request = list.get(i);
            request.setApplicantName(idName.get(request.getApplicant()));

            if (request.getRelaPeople() != null && !"".equals(request.getRelaPeople())) {   // 参与人
                List<People> relatePeopleList = new LinkedList<>();
                for (String relatePeopleId : request.getRelaPeople().split(",")) {
                    Integer contactId = Integer.valueOf(relatePeopleId);
                    People relatePeople = new People();
                    relatePeople.initPeople();
                    relatePeople.setContactId(contactId);
                    relatePeople.setName(idName.get(contactId));
                    relatePeopleList.add(relatePeople);
                }
                request.setRelaPeopleList(relatePeopleList);
            }

            list.set(i, request);
        }
    }

    private String getPeopleIds(List<Request> list) {
        List<Integer> result = new LinkedList<>();
        if (list.size() == 0) {
            return null;
        } else {
            Set<Integer> set = new HashSet<>();
            for (Request request : list) {
                set.add(request.getApplicant());        // 申请人
                if (request.getRelaPeople() != null && !"".equals(request.getRelaPeople())) {   // 参与人
                    for (String relatePeopleId : request.getRelaPeople().split(",")) {
                        set.add(Integer.valueOf(relatePeopleId));
                    }
                }
            }

            if (set.size() > 0) {
                result = new LinkedList<>(set);
            }
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < result.size(); i++) {
            sb.append(result.get(i));
            if (result.size() - i > 1) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

    @Override
    public List<Request> getTemplateRequestByDateScope(Integer templateId, String startDate, String endDate) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);
            ComponentDao componentDao = new ComponentImpl(connection);
            List<Request> requests = requestDao.selectTemplateRequestDetailByDateScope(templateId, startDate, endDate);
            return setCcAndComponents(ccDao, componentDao, requests);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getUserTemplateRequestListByDateScope(Integer companyInfoId, Integer templateId, String startDate, String endDate) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);
            ComponentDao componentDao = new ComponentImpl(connection);

            List<Request> requests = requestDao.selectUserTemplateRequestDetailByDateScope(companyInfoId, templateId, startDate, endDate);
            return setCcAndComponents(ccDao, componentDao, requests);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            EmailUtils.sendErrorMail("交接异常", JSONObject.toJSONString(e));
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getRequestListByIds(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);

            List<Request> list = requestDao.selectRequestByIds(query.getRequestIds());

            requestDecoration(list, query);

            return list;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Request> getRelatedRequestList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);
            ParticipantDao participantDao = new ParticipantDaoImpl(connection);
            List<Request> requests = requestDao.selectNewestRequestByIds(query.getCompanyId(), query.getRequestIds());
            if (Utils.isEmpty(requests)) {
                return requests;
            }

            requests = filterByFinished(requests);

            requests = filterByAuth(query, requests, flowDao, ccDao, participantDao, templateDao);

            requestDecoration(requests, query);

            List<Integer> requestIds = Utils.string2list(query.getRequestIds());
            requests.sort(Comparator.comparingInt(o -> requestIds.indexOf(requestIds.contains(o.getRequestDkey()) ? o.getRequestDkey() : o.getRequestAncestorId())));

            ApprovalUtils.replaceNewExpenseValue(requests);

            return requests;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Integer> filterPermissionRequest(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);
            ParticipantDao participantDao = new ParticipantDaoImpl(connection);
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            List<Request> requests = requestDao.selectNewestRequestByIds(query.getCompanyId(), query.getRequestIds());

            if (Utils.isEmpty(requests)) {
                return new ArrayList<>();
            }

            requests = filterByFinished(requests);

            requests = filterByAuth(query, requests, flowDao, ccDao, participantDao, templateDao);

            List<Integer> requestIds = Utils.string2list(query.getRequestIds());
            requests.sort(Comparator.comparingInt(o -> requestIds.indexOf(requestIds.contains(o.getRequestDkey()) ? o.getRequestDkey() : o.getRequestAncestorId())));

            return RequestUtils.getRequestIds(requests);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private List<Request> filterByFinished(List<Request> requests) {
        List<Request> list = new ArrayList<>();
        for (Request request : requests) {
            if (request.getFinished() == Finished.CALLING_BACK || request.getFinished() == Finished.DELETED) {
                continue;
            }
            list.add(request);
        }
        return list;
    }

    private List<Request> filterByAuth(Query query, List<Request> requests, FlowDao flowDao, CcDao ccDao, ParticipantDao participantDao, TemplateDao templateDao) throws Throwable {
        UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
        User user = userServicePrx.getUserByContactId(query.getContactId());
        if (UserUtils.isAdmin(user)) {
            return requests;
        }
        String requestIds = Utils.collection2string(RequestUtils.getRequestIds(requests));
        Map<Integer, List<Flow>> flowMap = flowDao.selectFlowMapByRequestIds(requestIds);
        Map<Integer, List<Cc>> ccMap = ccDao.selectBatchCc(requestIds);
        Map<Integer, List<Participant>> participateMap = participantDao.selectBatchParticipant(requestIds);
        List<User> subordinateList = userServicePrx.getAllSubordinateList(user.getContactId());
        List<Integer> allNormalContactIds = UserUtils.getContactIds(userServicePrx.getAllNormalUserList(query.getCompanyId()));

        List<Request> list = new ArrayList<>();
        for (Request request : requests) {
            // 申请人
            if (Objects.equals(request.getApplicantCiid(), user.getCompanyInfoId())) {
                list.add(request);
                continue;
            }
            // 审批人
            List<Flow> flows = flowMap.get(request.getRequestDkey());
            if (Utils.isEmpty(flows)) {
                flows = flowDao.selectFlowsByRequestId(request.getRequestDkey());
            }
            if (FlowUtils.isExistUserFlow(flows, user)) {
                list.add(request);
                continue;
            }
            // 抄送人
            if (request.getFinished() == Finished.AGREED || request.getFinished() == Finished.ARCHIVED) {
                List<Cc> ccList = ccMap.get(request.getRequestDkey());
                if (CcUtils.isExistUserCc(ccList, user)) {
                    list.add(request);
                    continue;
                }
            }
            // 参与人
            List<Participant> participants = participateMap.get(request.getRequestDkey());
            if (ParticipateUtils.isExistUser(participants, user)) {
                list.add(request);
                continue;
            }
            // 存在下属的
            if (Utils.isNotEmpty(subordinateList)) {
                for (User subUser : subordinateList) {
                    if (Objects.equals(subUser.getContactId(), request.getApplicant())) {
                        // 下属申请的
                        list.add(request);
                        break;
                    }
                    if (FlowUtils.isExistContactFlow(flows, subUser.getContactId())) {
                        // 下属审批的
                        list.add(request);
                        break;
                    }
                }
            }
            if (list.contains(request)) {
                continue;
            }
            Set<Integer> quitContactIds = filterQuitContactIds(allNormalContactIds, request, flows);
            if (Utils.isEmpty(quitContactIds)) {
                continue;
            }
            boolean hasPermission = userServicePrx.hasPermission(user.getContactId(), Utils.collection2string(quitContactIds));
            if (hasPermission) {
                list.add(request);
            }
        }
        return list;
    }

    private Set<Integer> filterQuitContactIds(List<Integer> normalIds, Request request, List<Flow> flows) {
        // 申请人或审批人已离职
        Set<Integer> quitContactIds = flows.stream().filter(flow -> !normalIds.contains(flow.getContactId())).map(Flow::getContactId).collect(Collectors.toSet());
        if (!normalIds.contains(request.getApplicant())) {
            quitContactIds.add(request.getApplicant());
        }
        return quitContactIds;
    }

    private List<Request> setCcAndComponents(CcDao ccDao, ComponentDao componentDao, List<Request> requests) throws SQLException {
        List<Integer> requestIds = RequestUtils.getRequestIds(requests);
        Map<Integer, List<Cc>> ccMap = ccDao.selectBatchCc(Utils.list2string(requestIds));
        Map<Integer, List<TemplateComponent>> componentMap = componentDao.selectComponentMapByRequestIds(Utils.list2string(requestIds));
        Map<Integer, Map<Integer, List<GroupContent>>> groupMap = componentDao.selectGroupComponentByRequestIds(Utils.list2string(requestIds));

        for (Request request : requests) {
            Map<Integer, List<GroupContent>> valueMap = groupMap.get(request.getRequestDkey());

            List<Cc> ccList = ccMap.get(request.getRequestDkey());
            List<TemplateComponent> templateComponents = componentMap.get(request.getRequestDkey());
            if (Utils.isNotEmpty(valueMap)) {
                for (TemplateComponent component : templateComponents) {
                    if (valueMap.containsKey(component.getNum())) {
                        List<GroupContent> groupContents = valueMap.get(component.getNum());
                        component.setValue(JSONObject.toJSONString(groupContents));
                    }
                }
            }
            request.setComponentsContent(templateComponents);
            request.setTemplateComponent(JSONObject.toJSONString(templateComponents));

            request.setCc(CcUtils.getDefaultCc(ccList));
            request.setCcTemp(CcUtils.getTempCc(ccList));
            request.setArchived(CcUtils.getArchived(ccList));
        }
        return requests;
    }

    @Override
    public void handleQuitRequestFlow(User quitUser) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            RequestDao requestDao = new RequestDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);
            List<Integer> requestIds = requestDao.selectUserNotApprovedRequestIds(quitUser.getCompanyId(), quitUser.getCompanyInfoId());

            logger.info("待处理审批流:{}", requestIds);
            if (Utils.isEmpty(requestIds)) {
                return;
            }
            List<Request> requests = requestDao.selectRequestByIds(Utils.list2string(requestIds));
            Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);

            User admin = userServicePrx.getAdminUser(quitUser.getCompanyId());
            Map<Integer, List<Flow>> flowMap = flowDao.selectFlowMapByRequestIds(Utils.list2string(requestIds));
            for (Integer requestId : requestIds) {
                Request request = requestMap.get(requestId);
                List<Flow> flows = flowMap.get(requestId);
                for (int i = 0; i < flows.size(); i++) {
                    Flow flow = flows.get(i);
                    if (flow.hasConfirmed() || !Objects.equals(flow.getCompanyInfoId(), quitUser.getCompanyInfoId())) {
                        continue;
                    }
                    // 移除离职审批人
                    flows.remove(flow);
                    List<Flow> flowsByOrdering = FlowUtils.getFlowsByOrdering(flows, flow.getOrdering());
                    if (Utils.isNotEmpty(flowsByOrdering)) {
                        logger.info("当前层级还有其他审批人，不改变后续审批顺序");
                        continue;
                    }
                    if (i == flows.size()) {
                        logger.info("最后一级审批人离职,交接给老板");
                        Flow adminFlow = new Flow(admin);
                        adminFlow.setRequestId(flow.getRequestId());
                        adminFlow.setIsApproved(flow.getIsApproved());
                        adminFlow.setOrdering(flow.getOrdering());
                        flows.add(adminFlow);
                        break;
                    }
                    for (int j = i; j < flows.size(); j++) {
                        Flow followFlow = flows.get(j);
                        followFlow.setOrdering(followFlow.getOrdering() - 1);
                    }
                    i--;
                }
                FlowUtils.transferRequestInfo(request, quitUser, flows);
            }
            List<Flow> allFlows = new ArrayList<>();
            for (List<Flow> flows : flowMap.values()) {
                allFlows.addAll(flows);
            }
            DBUtils.begin(connection);
            flowDao.deleteBatchFlowsByRequestIds(admin.getCompanyId(), Utils.list2string(requestIds));
            flowDao.insertFlows(allFlows);
            requestDao.updateRequestUsersBatch(requests, quitUser.getCompanyId());
            DBUtils.commit(connection);

        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            EmailUtils.sendErrorMail("交接异常", JSONObject.toJSONString(e));
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void handleQuitRequestCc(User user) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            RequestDao requestDao = new RequestDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);

            List<Integer> userContactIds = ListHelper.getContactIdList(userServicePrx.getAllMultiUserListByContactId(user.getContactId()));

            // 移除用户未归档审批的抄送人
            List<Integer> requestIds = ccDao.selectNeedToFileRequestIds(user.getCompanyId(), user.getCompanyInfoId());
            logger.info("开始移除抄送人:{}", requestIds);
            List<Request> requests = requestDao.selectRequestByIds(Utils.list2string(requestIds));
            removeCcFromRequests(user, ccDao, userContactIds, requestIds, requests);


            DBUtils.begin(connection);
            // 更新抄送人和审批状态
            requestDao.updateRequestCcBatch(requests);
            // 作废抄送状态
            ccDao.deleteUserCcStatus(requestIds, user.getCompanyInfoId());

            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            EmailUtils.sendErrorMail("交接异常", JSONObject.toJSONString(e));
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private void removeCcFromRequests(User user, CcDao ccDao, List<Integer> userContactIds, List<Integer> requestIds, List<Request> requests) throws SQLException {
        Map<Integer, List<Integer>> archivedIdMap = ccDao.selectArchivedCompanyInfoMap(Utils.list2string(requestIds));

        for (Request request : requests) {
            if (StringUtils.isBlank(request.getCc())) {
                continue;
            }
            List<Integer> contactIds = ListHelper.string2IntegerList(request.getCc());
            List<Integer> companyInfoIds = ListHelper.string2IntegerList(request.getCcCiid());

            boolean isChanged = contactIds.removeAll(userContactIds);
            if (!isChanged) {
                continue;
            }
            companyInfoIds.remove(user.getCompanyInfoId());

            request.setCc(Utils.isEmpty(contactIds) ? null : ListHelper.list2string(contactIds));
            request.setCcCiid(Utils.isEmpty(companyInfoIds) ? null : ListHelper.list2string(companyInfoIds));
            logger.info("移除审批{}抄送人:{}", request.getRequestDkey(), request.getCcCiid());
            if (request.getFinished() == Finished.AGREED) {
                List<Integer> archivedIds = archivedIdMap.get(request.getRequestDkey());
                if (Utils.isNotEmpty(archivedIds) && archivedIds.size() == companyInfoIds.size()) {
                    logger.info("其他人已归档,修改审批状态");
                    request.setFinished(Finished.ARCHIVED);
                }
            }
        }
    }

    @Override
    public Request getRequestDetail(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            CcDao ccDao = DaoFactory.getCcDao(connection);
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            LeaveDao leaveDao = new LeaveDaoImpl(connection);
            OutdoorDao outdoorDao = new OutdoorDaoImpl(connection);
            AppendSignDao appendSignDao = new AppendSignDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);
            ComponentDao componentDao = new ComponentImpl(connection);
            OvertimeDao overtimeDao = new OvertimeDaoImpl(connection);
            ExpenseDao expenseDao = new ExpenseDaoImpl(connection);


            // 前端传的模板版本更新次数, 用于判断老版本看新版本时抛更新提示的错误
            int userGeneration = Utils.isNull(query.getGeneration()) ? 0 : query.getGeneration();
            User user = userServicePrx.getUserByContactId(query.getContactId());
            RequestDao requestDao = new RequestDaoImpl(connection);
            Request request = requestDao.selectRequestDetailById(query.getRequestId());

            // 获取套件信息（后面自定义模版应该从组件内容进行提取）
            setRequestSuite(request, leaveDao, outdoorDao, appendSignDao, overtimeDao, expenseDao);

            // 获取审批流
            List<Flow> flows = flowDao.selectFlowsByRequestId(request.getRequestDkey());
            request.setFlows(flows);

            // 设置请假、销假信息
            setLeaveInfo(request);

            // 设置审批人信息
            FlowUtils.transferRequestInfo(request, user, flows);

            // 抄送人与归档信息
            setCcInfos(ccDao, request, user);

            //获得审批对应的模板
            request = templateDao.getTemplateDetailByRequests(request, user);

            request = templateDao.getLatestTemplateByAncestorId(request);

            // 获取审批内容
            setComponentsContent(componentDao, request);

            // 驳回链
            if (StringUtils.isNotEmpty(request.getRefuseChain())) {
                request.setRefuseChainObj(templateDao.getRefuseChainDetail(request.getRefuseChain()));
            }
            // 已撤销的审批,查出最新的审批
            if (Objects.equals(request.getIsResubmit(), 1)) {
                List<Request> requests = requestDao.selectNewestRequestByIds(user.getCompanyId(), String.valueOf(request.getRequestDkey()));
                Request newestRequest = Utils.getFirst(requests);
                if (Utils.isNotNull(newestRequest)) {
                    newestRequest.setCcList(ccDao.selectCcListByRequestId(newestRequest.getRequestDkey()));
                    request.setNewestRequest(newestRequest);
                }
            }
            // 消红点
            RocketUtils.clearUserRedPoint(request.getRequestDkey(), user);

            adjust(query, userGeneration, user, request);

            try {
                Map<Integer, Request> requestMap = new HashMap<>();
                requestMap.put(request.getRequestDkey(), request);
                setSummaryInfo(connection, requestMap, query);
            } catch (Throwable throwable) {
                logger.info("request:{}", JSONObject.toJSONString(request));
                logger.error(throwable.getMessage(), throwable);
            }

            simplifyData(query, request);

            return request;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void modifyApprovalRelate(RelateHistory relateHistory) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RelateHistoryDao relateDao = new RelateHistoryDaoImpl(connection);

            relateDao.insertApprovalRelate(relateHistory);
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<RelateHistory> getRelateHistory(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RelateHistoryDao relateHistoryDao = new RelateHistoryDaoImpl(connection);
            return relateHistoryDao.getRelateHistory(query);
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }


    private void adjust(Query query, int userGeneration, User user, Request request) throws Throwable {
        // 兼容旧版审批流
        adjustOldVersionFlows(request, user);

        // 获取相关人群信息
        if (!query.canHidePeopleList()) {
            getNameOfPeople(request, user.getCompanyId());
        }

        ApprovalUtils.replaceNewExpenseValue(request, userGeneration);

        ApprovalUtils.isNewCheckInGeneration(request, userGeneration);

        request.setOperations(OperationUtils.getOperations(user, request));

        if (!LookAuth.checkUserIsCanSeeRequest(user, request)) {
            throw new RpcServerLogicalException(2, "无权查看");
        }
    }

    private void simplifyData(Query query, Request request) {
        if (query.canHidePeopleList()) {
            request.setAllJudger(null);
            request.setCc(null);
            request.setCcCiid(null);
            request.setWhoConfirm(null);
            request.setWhoConfirmCiid(null);
            request.setWhoRefused(null);
            request.setWhoRefusedCiid(null);
            request.setWhoTheNext(null);
            request.setWhoTheNextCiid(null);
            request.setCheckedTime(null);
            request.setFinallyConfirmedTime(null);
            request.setCreateTimestamp(null);
            request.setRequestName(null);
            request.setRequestStep(null);
            request.setLatestApprovedTime(null);
            request.setCreateTime(null);
        }

        // 删掉一些字段,看看有没有问题
        // 2020年4月26日 19:37:52
        if (Objects.equals(query.getCompanyId(), 12) || ApprovalUtils.isTestCompany(query.getCompanyId())) {
            request.setTemplateComponent(null);
            request.setPeopleList(null);
            request.setRelaPeopleList(null);
            request.setRelaPeopleCiid(null);
            request.setDepartmentId(null);
            request.setMultiChosen(null);
            request.setRequestName(null);
            request.setTemplateTips(null);
            request.setTemplateMetaName(null);
            request.setWhoConfirm(null);
            request.setWhoConfirmCiid(null);
            request.setCc(null);
            request.setCcCiid(null);
            request.setAllJudger(null);
            request.setAllJudgerCiid(null);
            request.setCheckedTime(null);
            request.setCreateTimestamp(null);
            request.setLatestApprovedTime(null);
            request.setAmountTop(null);
            request.setAncestorId(null);
            request.setRequestStep(null);
            request.setNewestRequest(null);
        }
    }

    private void adjustOldVersionFlows(Request request, User user) {
        try {
            // 复制一份
            List<Flow> flows = BeanUtils.pos2dtos(request.getFlows(), Flow.class);
            if (!isExistMultiFlows(flows)) {
                return;
            }
            flows.sort((o1, o2) -> {
                if (o1.getOrdering() != o2.getOrdering()) {
                    return o1.getOrdering() - o2.getOrdering();
                }
                int i1 = o1.getIsApproved();
                int i2 = o2.getIsApproved();
                if (StringUtils.isNotBlank(o1.getIsApprovedAt())) {
                    i1 = Integer.MAX_VALUE;
                }
                if (Objects.equals(o1.getCompanyInfoId(), user.getCompanyInfoId())) {
                    i1 = Integer.MAX_VALUE - 1;
                }
                if (StringUtils.isNotBlank(o2.getIsApprovedAt())) {
                    i2 = Integer.MAX_VALUE;
                }
                if (Objects.equals(o2.getCompanyInfoId(), user.getCompanyInfoId())) {
                    i2 = Integer.MAX_VALUE - 1;
                }
                return i2 - i1;
            });
            int maxOrdering = FlowUtils.getMaxOrdering(flows);
            for (int ordering = 1; ordering <= maxOrdering; ordering++) {
                List<Flow> currentFlows = FlowUtils.getFlowsByOrdering(flows, ordering);
                if (currentFlows.get(0).getType() != Flow.MODE_OR) {
                    continue;
                }
                String confirmedTime = null;
                for (Flow currentFlow : currentFlows) {
                    if (currentFlow.hasConfirmed()) {
                        confirmedTime = currentFlow.getIsApprovedAt();
                        break;
                    }
                }
                if (StringUtils.isNotBlank(confirmedTime)) {
                    for (Flow currentFlow : currentFlows) {
                        currentFlow.setIsApprovedAt(confirmedTime);
                        currentFlow.setIsApproved(Flow.CONFIRM);
                    }
                }
            }
            FlowUtils.transferRequestInfo(request, user, flows);
        } catch (Throwable e) {
            // 2020年1月20日 13:40:37
            logger.error(e.getMessage(), e);
            EmailUtils.sendMail("兼容审批流出错", e);
        }
    }

    private boolean isExistMultiFlows(List<Flow> flows) {
        for (Flow flow : flows) {
            if (flow.getType() == Flow.MODE_AND || flow.getType() == Flow.MODE_OR) {
                return true;
            }
        }
        return false;
    }

    private void setRequestSuite(Request request, LeaveDao leaveDao, OutdoorDao outdoorDao, AppendSignDao appendSignDao, OvertimeDao overtimeDao, ExpenseDao expenseDao) {
        try {
            switch (request.getDefaultType()) {
                case Template.LEAVE:
                case Template.COMPENSATORY_LEAVE:
                case Template.DAYS_OFF:
                    Leave leave = leaveDao.selectLastLeaveByRequestId(request.getRequestDkey());
                    request.setLeave(leave);
                    break;
                case Template.OUTDOOR:
                case Template.BUSINESS_TRIP:
                    Outdoor outdoor = outdoorDao.selectLastOutdoorByRequestId(request.getRequestDkey());
                    request.setOutdoor(outdoor);
                    StringBuilder sb = new StringBuilder();
                    if (StringUtils.isNotEmpty(outdoor.getSrcCoordinate())) {
                        sb.append(outdoor.getSrcCoordinate());
                    }
                    if (StringUtils.isNotEmpty(outdoor.getDestCoordinate())) {
                        if (StringUtils.isNotEmpty(sb)) {
                            sb.append("#");
                        }
                        sb.append(outdoor.getDestCoordinate());
                    }
                    request.setOuterPosition(sb.toString());
                    break;
                case Template.APPEND_SIGN:
                    List<AppendSign> appendSigns = appendSignDao.selectAppendSignsByRequestId(request.getRequestDkey());
                    request.setAppendSigns(appendSigns);
                    break;
                case Template.WORK_OVERTIME:
                    List<Overtime> overtimes = overtimeDao.selectOvertimesByRequestId(request.getRequestDkey());
                    request.setOvertimes(overtimes);
                    break;
                case Template.EXPENSES:
                case Template.PURCHASE:
                    List<Expense> expenses = expenseDao.selectExpensesByRequestId(request.getRequestDkey());
                    request.setExpenses(expenses);
                    break;
                default:
                    break;
            }
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            EmailUtils.sendMail("获取套件出错", e);
        }
    }

    private void setLeaveInfo(Request request) {
        Leave leave = request.getLeave();
        if (Utils.isNull(leave)) {
            return;
        }
        if (Objects.equals(request.getDefaultType(), Template.DAYS_OFF)) {
            return;
        }
        request.setLeaveDuration(leave.getLeaveTimeDetail());
        request.setIsLeavePause(leave.getIsLeavePause());
    }

    private void setCcInfos(CcDao ccDao, Request request, User user) throws Throwable {
        List<Cc> ccList = ccDao.selectCcListByRequestId(request.getRequestDkey());
        request.setCcList(ccList);
        if (Utils.isEmpty(ccList)) {
            return;
        }
        // 为了让前端抄送人另一个身份,显示归档按钮,这里将抄送人id修改为另一个身份的id
        for (Cc cc : ccList) {
            if (cc.getCcCiid() == user.getCompanyInfoId()) {
                // 修改ccId为另一个身份的id,让前端支持其他身份显示归档按钮
                cc.setCcId(user.getContactId());
            }
        }
        request.setCc(CcUtils.getCc(ccList));
    }

    private void setComponentsContent(ComponentDao componentDao, Request request) throws SQLException {
        List<TemplateComponent> components = componentDao.selectComponentByRequestId(request.getRequestDkey());
        List<TemplateComponent> templateComponents = JSONObject.parseArray(request.getTemplateComponent(), TemplateComponent.class);
        Map<Integer, List<GroupContent>> groupContentMap = componentDao.selectGroupComponentByRequestId(request.getRequestDkey());
        request.setComponentsContent(ComponentUtils.mergeComponents(templateComponents, components, groupContentMap));
    }

    private void getNameOfPeople(Request request, Integer companyId) {
        try {
            // 需要获取名字的people
            List<String> peopleList = collectAllPeople(request);
            if (peopleList.isEmpty()) {
                return;
            }

            String contactIds = ListHelper.list2string(peopleList);

            UserServicePrx userService = ServantUtils.getObject(UserServicePrx.class);
            List<User> users = userService.getUserBaseInfoListByContactIds(companyId, contactIds);

            Map<Integer, User> userMap = users.stream().collect(Collectors.toMap(User::getContactId, user -> user, (a, b) -> b));

            // 处理申请人
            handleApplicant(request, userMap);

            // 处理参与人
            if (StringUtils.isNotEmpty(request.getRelaPeople())) {
                handleRelatePeople(request, userMap);
            }

            // 处理审批人
            if (StringUtils.isNotEmpty(request.getAllJudger())) {
                handleAllJudger(request, userMap);
            }

            // 处理抄送人
            if (StringUtils.isNotEmpty(request.getCc())) {
                handleCc(request, userMap);
            }
        } catch (Throwable throwable) {
            logger.error(throwable.getMessage(), throwable);
        }
    }

    private List<String> collectAllPeople(Request request) {
        List<String> peopleList = new LinkedList<>();

        // 申请人
        peopleList.add(String.valueOf(request.getApplicant()));

        // 审批人
        if (StringUtils.isNotEmpty(request.getAllJudger())) {
            peopleList.addAll(Arrays.asList(request.getAllJudger().split(",")));
        }

        // 参与人
        if (StringUtils.isNotEmpty(request.getRelaPeople())) {
            peopleList.addAll(Arrays.asList(request.getRelaPeople().split(",")));
        }

        // 抄送人
        if (StringUtils.isNotEmpty(request.getCc())) {
            peopleList.addAll(Arrays.asList(request.getCc().split(",")));
        }

        return peopleList;
    }

    private void handleApplicant(Request request, Map<Integer, User> result) {
        int applicant = request.getApplicant();
        if (result.containsKey(applicant)) {
            request.setApplicantName(result.get(applicant).getContactName());
        }
    }

    private void handleRelatePeople(Request request, Map<Integer, User> result) {
        List<People> relatePeopleList = new LinkedList<>();
        for (String relatePeopleId : request.getRelaPeople().split(",")) {
            People people = new People();
            int key = Integer.parseInt(relatePeopleId);
            if (result.containsKey(key)) {
//				if (Objects.equals(request.getWithoutContact(), 1)) {
//					logger.info("无需用户信息");
//				} else {
//					people.setName(result.get(key).getContactName());
//					people.initPeople();
//				}
                people.setName(result.get(key).getContactName());
                people.initPeople();
                people.setContactId(key);
                relatePeopleList.add(people);
            }
        }
        request.setRelaPeopleList(relatePeopleList);
    }

    private void handleAllJudger(Request request, Map<Integer, User> result) {
        List<People> allJudger = new LinkedList<>();
        String[] allJudgerArray = request.getAllJudger().split(",");
        // 审批流顺序
        for (String anAllJudgerArray : allJudgerArray) {
            People people = new People();
            int key = Integer.parseInt(anAllJudgerArray);
            if (result.containsKey(key)) {
                if (Objects.equals(request.getWithoutContact(), 1)) {
                    logger.info("无需用户信息");
                } else {
                    people.setName(result.get(key).getContactName());
                    people.initPeople();
                }
                people.setContactId(key);
                allJudger.add(people);
            }
        }
        request.setPeopleList(allJudger);
    }

    private void handleCc(Request request, Map<Integer, User> userMap) {
        if (Objects.equals(request.getWithoutContact(), 1)) {
            // 无需设置抄送人用户信息
            return;
        }
        if (Utils.isEmpty(request.getCcList())) {
            // 没有抄送人
            return;
        }
        for (Cc cc : request.getCcList()) {
            int key = cc.getCcId();
            if (userMap.containsKey(key)) {
                cc.setCcName(userMap.get(key).getContactName());
            }
        }
    }
}
